package xyz.bali16.application.controller;

import cn.hutool.core.util.StrUtil;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.core.toolkit.StringUtils;
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;

import com.google.common.collect.Sets;
import com.mysql.cj.protocol.ResultsetRow;
import io.swagger.annotations.Api;
import io.swagger.annotations.ApiImplicitParam;
import io.swagger.annotations.ApiImplicitParams;
import io.swagger.annotations.ApiOperation;
import lombok.AllArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.security.access.prepost.PreAuthorize;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.util.CollectionUtils;
import org.springframework.web.bind.annotation.*;
import xyz.bali16.application.config.prop.AuthProp;
import xyz.bali16.application.core.enums.ApiEnum;
import xyz.bali16.application.core.model.Result;
import xyz.bali16.application.entity.Menu;
import xyz.bali16.application.entity.Role;
import xyz.bali16.application.entity.RoleMenu;
import xyz.bali16.application.entity.User;

import xyz.bali16.application.model.role.RoleAddParam;
import xyz.bali16.application.model.role.RoleMenuUpdateParam;
import xyz.bali16.application.model.role.RolePageParam;
import xyz.bali16.application.model.role.RoleUpdateParam;
import xyz.bali16.application.model.vo.MenuTreeListVo;
import xyz.bali16.application.service.MenuService;
import xyz.bali16.application.service.RoleMenuService;
import xyz.bali16.application.service.RoleService;
import xyz.bali16.application.service.UserRoleService;

import javax.validation.Valid;

import java.util.*;
import java.util.stream.Collectors;

import static xyz.bali16.application.core.model.Result.*;
import static xyz.bali16.application.core.utils.ResultUtils.errorLog;

@RestController
@RequestMapping(BaseController.API + "role")
@Api(tags = "角色接口")
@AllArgsConstructor
@Slf4j
public class RoleController extends BaseController {


    private final RoleService roleService;
    private final UserRoleService userRoleService;
    private final AuthProp authProp;

    private final RoleMenuService roleMenuService;

    private final MenuService menuService;

    @GetMapping("/list")
    @ApiOperation("获取所有角色")
    //@PreAuthorize("@auth.permission('sys:role:query')")
    public Result<List<Role>> list() {
        return success(ApiEnum.GET_SUCCESS, roleService.list());
    }

    @GetMapping
    //@PreAuthorize("@auth.permission('sys:role:query')")
    @ApiOperation("分页条件查询角色")
    public Result<IPage<Role>> pageQuery(@Valid RolePageParam param) {
        LambdaQueryWrapper<Role> wrapper = Wrappers.<Role>lambdaQuery()
                .ne(Role::getCode, authProp.getSuperRoleCode());
        if (!StrUtil.isEmpty(param.getName())) {
            wrapper.like(Role::getName, param.getName());
        }
        if (!StrUtil.isEmpty(param.getRoleCode())) {
            wrapper.like(Role::getCode, param.getRoleCode());
        }
        Integer status = param.getStatus();
        if (status != null && (status == 1 || status == 0)) {
            wrapper.eq(Role::getStatus, param.getStatus());
        }
        wrapper.eq(Role::getDeleted, 0)
                .orderByDesc(Role::getGmtCreated);
        Page<Role> page = new Page<>(param.getCurrent(), param.getSize());
        page = roleService.page(page, wrapper);

        List<Role> roles = page.getRecords(); // 处理用户所拥有的菜单
        System.out.println(roles);
        for (Role role : roles) {
            List<RoleMenu> menus = roleMenuService.list((Wrappers.<RoleMenu>lambdaQuery().eq(RoleMenu::getRoleId, role.getRoleId())));
            System.out.println("menus");
            System.out.println(menus);
            if (CollectionUtils.isEmpty(menus)) {
                role.setMenu(Collections.emptyList());
                continue;
            }
            role.setMenu(menus.stream().map(x -> x.getMenuId()).collect(Collectors.toList()));
            System.out.println(role);
        }

        return success(ApiEnum.GET_SUCCESS, page);
    }
    //
    //@GetMapping("/role-menu")
    //////@PreAuthorize("@auth.permission('role:setMenu')")
    //@ApiOperation("分配角色时, 查询当前角色的菜单和权限")
    //public Result<RoleMenuVo> getRoleMenu(@RequestParam("roleId") String roleId) {
    //    try {
    //        RoleMenuVo roleMenuVo = new RoleMenuVo();
    //        List<MenuTree> menuTreeByCurrentUser = menuService.getMenuTreeByCurrentUser(true);
    //
    //        LambdaQueryWrapper<RoleMenu> wrapper = Wrappers.<RoleMenu>lambdaQuery()
    //                .eq(RoleMenu::getRoleId, roleId);
    //        List<RoleMenu> roleMenus = roleMenuService.list(wrapper);
    //        Set<String> menuIds = Sets.newHashSet();
    //        for (RoleMenu roleMenu : roleMenus) {
    //            menuIds.add(roleMenu.getMenuId());
    //        }
    //        roleMenuVo.setMenuIds(menuIds);
    //        roleMenuVo.setMenuTree(menuTreeByCurrentUser);
    //        return success(ApiEnum.GET_SUCCESS, roleMenuVo);
    //    } catch (Exception e) {
    //        errorLog(log, e, "获取角色 '{}' 权限菜单信息失败", roleId);
    //        return failure(ApiEnum.GET_SUCCESS, e);
    //    }
    //}

    @PutMapping("/role-menu")
    //@PreAuthorize("@auth.permission('sys:role:setMenu')")
    @ApiOperation("分配角色菜单和权限")
    public Result<String> updateRoleMenu(@RequestBody @Valid RoleMenuUpdateParam param) {
        try {
            roleService.updateRoleMenu(param);
            return response(ApiEnum.UPDATE_SUCCESS, "修改角色权限成功");
        } catch (Exception e) {
            errorLog(log, e, "更新角色权限 '{}' 失败 {}", param.getRoleId(), e.getMessage());
            return failure(ApiEnum.UPDATE_ERROR, "修改角色权限失败.", e);
        }
    }

    @PostMapping
    //@PreAuthorize("@auth.permission('sys:role:add')")
    @Transactional
    @ApiOperation("添加角色")
    public Result<String> add(@RequestBody @Valid RoleAddParam param) {
        try {
            roleService.addRole(param);
            Role newRole = roleService.getOne(Wrappers.<Role>lambdaQuery().eq(Role::getCode, param.getCode()));
            assignRoleMenu(newRole.getRoleId(), param.getMenu());
            return response(ApiEnum.ADD_SUCCESS, "添加角色成功");
        } catch (Exception e) {
            errorLog(log, e, "添加角色 '{}' 信息失败 {}", param.getCode(), e.getMessage());
            return failure(ApiEnum.ADD_ERROR, "添加角色失败", e);
        }
    }

    @PutMapping
    @Transactional
    //@PreAuthorize("@auth.permission('sys:role:update')")
    @ApiOperation("修改角色")
    public Result<String> update(@RequestBody @Valid RoleUpdateParam param) {
        System.out.println(param);
        System.out.println(param.getMenu());
        try {
            roleService.updateRole(param);
            assignRoleMenu(param.getRoleId(), param.getMenu());
            return response(ApiEnum.UPDATE_SUCCESS, "更新角色成功");
        } catch (Exception e) {
            errorLog(log, e, "更新角色 '{}' 信息失败 {}", param.getRoleId(), e.getMessage());
            return failure(ApiEnum.UPDATE_ERROR, "更新角色失败.", e);
        }
    }

    @PutMapping("{roleId}/{status}")
    //@PreAuthorize("@auth.permission('sys:role:update:status')")
    @ApiOperation("修改角色状态")
    @ApiImplicitParams({
            @ApiImplicitParam(name = "roleId", value = "角色id", paramType = "path", required = true),
            @ApiImplicitParam(name = "status", value = "状态（1启用, 0停用）", paramType = "path", required = true)
    })
    public Result<String> updateStatus(@PathVariable("roleId") String roleId,
                                       @PathVariable("status") Integer status) {
        String message = status == 1 ? "启用" : "禁用";
        try {
            roleService.updateStatus(roleId, status);
            return success(ApiEnum.UPDATE_SUCCESS, message + "成功");
        } catch (Exception e) {
            errorLog(log, e, "修改角色状态失败. {}", e.getMessage());
            return failure(ApiEnum.UPDATE_ERROR, message + "失败", e);
        }
    }

    @DeleteMapping("/{roleId}")
    //@PreAuthorize("@auth.permission('sys:role:delete')")
    @ApiOperation("删除角色")
    @ApiImplicitParam(name = "roleId", value = "角色id", paramType = "path", required = true)
    public Result<String> delete(@PathVariable("roleId") String roleId) {
        try {
            roleService.deleteRole(roleId);
            return response(ApiEnum.DELETE_SUCCESS);
        } catch (Exception e) {
            errorLog(log, e, "删除角色失败. {}", e.getMessage());
            return failure(ApiEnum.DELETE_ERROR, "删除失败", e);
        }
    }


    public Result<String> assignRoleMenu(String roleId, List menuIds) {
        if (CollectionUtils.isEmpty(menuIds)) {
            roleService.addRoleMenu(roleId, Collections.emptyList());
            return null;
        }
        String menuIdStr = menuIds.toString();
        List<String> menuIdsList = new ArrayList<>();
        try {
            if (StringUtils.isNotBlank(menuIdStr) && !menuIdStr.equals("[]")) {
                menuIdStr = menuIdStr.substring(1, menuIdStr.length() - 1);
                System.out.println("menuIdStr: " + menuIdStr);
                String[] menuIdArray = menuIdStr.split(",");
                for (int i = 0; i < menuIdArray.length; i++) {// 去除过滤后的空格
                    menuIdArray[i] = menuIdArray[i].trim();
                }
                menuIdsList = Arrays.asList(menuIdArray);
                System.out.println(menuIdsList);
                roleService.addRoleMenu(roleId, menuIdsList);
                return Result.success("分配权限成功");
            }
        } catch (Exception e) {
            return Result.failure("分配权限失败");
        }
        return Result.failure("分配权限失败");
    }


    @PostMapping("/assign/menu/list")
    @ResponseBody
    //@PreAuthorize("@auth.permission('sys:role:assign:menu:query')")
    public List<MenuTreeListVo> assignRole(String roleId) {
        List<MenuTreeListVo> listVos = new ArrayList<>();
        List<Menu> allMenus = menuService.list(Wrappers.<Menu>lambdaQuery().eq(Menu::getStatus, 1)); // 获取状态正常的menu
        List<Menu> hasMenus = roleService.findMenusByRoleId(roleId);
        for (Menu menu : allMenus) {
            MenuTreeListVo vo = new MenuTreeListVo();
            vo.setId(menu.getId());
            vo.setName(menu.getMenuName());
            vo.setParentId(menu.getParentId());
            for (Menu hasMenu : hasMenus) {
                //有权限则选中
                if (hasMenu.getId().equals(menu.getId())) {
                    vo.setChecked(true);
                    break;
                }
            }
            listVos.add(vo);
        }
        return listVos;
    }
}
